﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;

using SD.LLBLGen.Pro.ORMSupportClasses;
using SD.LLBLGen.Pro.QuerySpec;
using SD.LLBLGen.Pro.QuerySpec.Adapter;

using VNet.VisiSuite.Common.Resource;
using VNet.VisiSuite.Service.Contact.Enum;
using VNet.VisiSuite.Service.Contact.Message.Base;
using VNet.VisiSuite.Service.Contact.Message.Item;
using VNet.VisiSuite.VisiBoard.Dal.DatabaseSpecific;
using VNet.VisiSuite.VisiBoard.Dal.EntityClasses;
using VNet.VisiSuite.VisiBoard.Dal.FactoryClasses;
using VNet.VisiSuite.VisiBoard.Dal.HelperClasses;

using VNet.VisiSuite.Common.Logger;
using VNet.VisiSuite.Service.Contact.Message;

namespace VNet.VisiSuite.VisiBoard.BusinessLogic
{
    class ClientSyncUtil
    {

        public static List<TableDataChangeItem> tableDataChanges()
        {
            var table_data_changes = new List<TableDataChangeItem>();
            using (var adapter = new DataAccessAdapter())
            {
                try
                {
                    var qf = new QueryFactory();
                    var qry = qf.TableDataChange;
                    var tdcc = adapter.FetchQuery(qry);
                    if (tdcc != null)
                    {
                        foreach (TableDataChangeEntity entity in tdcc)
                        {
                            table_data_changes.Add(new TableDataChangeItem
                            {
                                TableName = entity.TableName,
                                TimeStamp = entity.TimeStamp
                            });
                        }
                    }
                }
                catch (Exception ex)
                {
                    FileLog.Error("tableDataChanges() - ", ex);
                }
            }

            return table_data_changes;
        }

        public static GetDataResponse<LocalData> PreSyncFromClientToServer()
        {
            var qf = new QueryFactory();
            var cellShiftQuery = qf.CellShift.Where(CellShiftFields.SyncStatus != (byte)SyncStatus.InSync);
            var braiderProductQuery = qf.BraiderProduct.Where(BraiderProductFields.SyncStatus != (byte)SyncStatus.InSync);
            var production_history_qry = qf.ProductionHistory.Where(ProductionHistoryFields.SyncStatus != (byte)SyncStatus.InSync).WithPath(ProductionHistoryEntity.PrefetchPathCellShift);
            var productionHistoryDowntimeEventQuery = qf.ProductionHistoryDowntimeEvent
                .WithPath(ProductionHistoryDowntimeEventEntity.PrefetchPathProductionHistory)
                .Where(ProductionHistoryDowntimeEventFields.SyncStatus != (byte)SyncStatus.InSync);

            var result = new LocalData();

            using (var adapter = new DataAccessAdapter())
            {
                try
                {
                    adapter.StartTransaction(IsolationLevel.ReadCommitted, "PreSyncFromClientToServer");

                    var cellShifts = (EntityCollection<CellShiftEntity>)adapter.FetchQuery(cellShiftQuery);
                    var braiderProducts = (EntityCollection<BraiderProductEntity>)adapter.FetchQuery(braiderProductQuery);
                    var productionHistories = (EntityCollection<ProductionHistoryEntity>)adapter.FetchQuery(production_history_qry);
                    var productionHistoryDowntimeEvents = (EntityCollection<ProductionHistoryDowntimeEventEntity>)adapter.FetchQuery(productionHistoryDowntimeEventQuery);
                    var cell_status = ((EntityCollection<CellStatusEntity>)adapter.FetchQuery(qf.CellStatus)).FirstOrDefault();

                    foreach (var item in cellShifts)
                    {
                        item.SyncStatus = (byte)SyncStatus.SyncInProgress;
                        result.CellShifts.Add(new CellShiftItem
                        {
                            ClientId = item.CellShiftId,
                            CellShiftId = item.ServerId ?? 0,
                            AreaShiftId = item.AreaShiftId,
                            CellId = item.CellId,
                            StartTime = item.StartTime,
                            EndTime = item.EndTime,
                        });
                    }

                    foreach (var item in braiderProducts)
                    {
                        item.SyncStatus = (byte)SyncStatus.SyncInProgress;
                        result.BraiderProducts.Add(new BraiderProductItem
                        {
                            BraiderProductId = item.ServerId ?? 0,
                            ClientId = item.BraiderProductId,
                            OperatorId = item.OperatorId,
                            BraiderNumber = item.BraiderNumber,
                            HoseSpec = item.HoseSpec,
                            HoseSize = item.HoseSize,
                            HoseCount = item.HoseCount,
                            BraiderType = item.BraiderType,
                            FeetPerMinute = item.FeetPerMinute,
                            CarrierCount = item.CarrierCount,
                            DeckCount = item.DeckCount,
                            Split = item.Split,
                        });
                    }

                    foreach (var item in productionHistories)
                    {
                        item.SyncStatus = (byte)SyncStatus.SyncInProgress;
                        result.ProductionHistories.Add(new ProductionHistoryItem
                        {
                            ClientId = item.ProductionHistoryId,
                            ProductionHistoryId = item.ServerId ?? 0,
                            CellShiftClientId = item.CellShiftId,
                            CellShiftId = item.CellShift.ServerId ?? 0,
                            ReasonCodeId = item.ReasonCodeId,
                            ProductionPlanId = item.ProductionPlanId,
                            BraiderProductId = item.BraiderProductId,
                            Operators = item.Operators,
                            WorkContent = item.WorkContent,
                            StartTime = item.StartTime,
                            EndTime = item.EndTime,
                            DowntimeAckTime = item.DowntimeAckTime,
                            VisiBoxKey = item.VisiBoxKey,
                        });
                    }

                    foreach (var item in productionHistoryDowntimeEvents)
                    {
                        item.SyncStatus = (byte)SyncStatus.SyncInProgress;
                        result.ProductionHistoryDowntimeEvents.Add(new ProductionHistoryDowntimeEventItem
                        {
                            ClientId = item.ProductionHistoryDowntimeEventId,
                            ProductionHistoryDowntimeEventId = item.ServerId ?? 0,
                            ProductionHistoryClientId = item.ProductionHistoryId,
                            ProductionHistoryServerId = item.ProductionHistory.ServerId,
                            ReasonCodeId = item.ReasonCodeId,
                            EventTime = item.EventTime,
                            VisiBoxKey = item.VisiBoxKey,
                        });
                    }

                    if (cell_status != null)
                    {
                        result.CellStatus = new CellStatusItem
                        {
                            CellStatusId = cell_status.CellStatusId,
                            CellId = cell_status.CellId,
                            ReasonCodeId = cell_status.ReasonCodeId,
                            Status = cell_status.Status,
                            Offline = cell_status.Offline,
                            EventTime = cell_status.EventTime,
                            Flags = cell_status.Flags,
                            TimeStamp = cell_status.TimeStamp
                        };
                    }

                    adapter.SaveEntityCollection(cellShifts);
                    adapter.SaveEntityCollection(braiderProducts);
                    adapter.SaveEntityCollection(productionHistories);
                    adapter.SaveEntityCollection(productionHistoryDowntimeEvents);

                    adapter.Commit();
                    return new GetDataResponse<LocalData> { Success = true, Data = result };
                }
                catch (Exception e)
                {
                    adapter.Rollback();
                    FileLog.Error("PreSyncFromClientToServer() - ", e);
                    return new GetDataResponse<LocalData> { Error = new ServiceError { Description = ErrorMessages.PrepareSyncClientServerError } };
                }
            }
        }

        public static ServiceBaseResponse PostSyncFromClientToServer(SyncDataFromClientResponse response)
        {

            // NOTE THAT ONLY THE PK (ServerId) SHOULD BE USED FROM THE DATA IN response.

            var qf = new QueryFactory();
            var cell_shift_qry = qf.CellShift
                .Where(CellShiftFields.CellShiftId.In(response.LocalData.CellShifts.Select(t => t.ClientId)));
            var braider_product_qry = qf.BraiderProduct
                .Where(BraiderProductFields.BraiderProductId.In(response.LocalData.BraiderProducts.Select(t => t.ClientId)));
            var production_history_qry = qf.ProductionHistory
                .Where(ProductionHistoryFields.ProductionHistoryId.In(response.LocalData.ProductionHistories.Select(t => t.ClientId)));
            var production_history_downtime_event_qry = qf.ProductionHistoryDowntimeEvent
                .Where(ProductionHistoryDowntimeEventFields.ProductionHistoryDowntimeEventId.In(response.LocalData.ProductionHistoryDowntimeEvents.Select(t => t.ClientId)));

            using (var adapter = new DataAccessAdapter())
            {
                try
                {
                    adapter.StartTransaction(IsolationLevel.ReadCommitted, "PostSyncFromClientToServer");
                    
                    var cell_shifts = (EntityCollection<CellShiftEntity>)adapter.FetchQuery(cell_shift_qry);
                    foreach (var e in cell_shifts)
                    {
                        if (e.SyncStatus == (byte)SyncStatus.SyncInProgress)
                            e.SyncStatus = (byte)SyncStatus.InSync;
                        if (!e.ServerId.HasValue)
                        {
                            var item = response.LocalData.CellShifts.FirstOrDefault(t => t.ClientId == e.CellShiftId);
                            if (item != null)
                                e.ServerId = item.CellShiftId;
                        }
                    }
                    adapter.SaveEntityCollection(cell_shifts);

                    var braider_products = (EntityCollection<BraiderProductEntity>)adapter.FetchQuery(braider_product_qry);
                    foreach (var e in braider_products)
                    {
                        if (e.SyncStatus == (byte)SyncStatus.SyncInProgress)
                            e.SyncStatus = (byte)SyncStatus.InSync;
                        if (!e.ServerId.HasValue)
                        {
                            var item = response.LocalData.BraiderProducts.FirstOrDefault(t => t.ClientId == e.BraiderProductId);
                            if (item != null)
                                e.ServerId = item.BraiderProductId;
                        }
                    }
                    adapter.SaveEntityCollection(braider_products);

                    var production_histories = (EntityCollection<ProductionHistoryEntity>)adapter.FetchQuery(production_history_qry);
                    foreach (var e in production_histories)
                    {
                        if (e.SyncStatus == (byte)SyncStatus.SyncInProgress)
                            e.SyncStatus = (byte)SyncStatus.InSync;
                        if (!e.ServerId.HasValue)
                        {
                            var item = response.LocalData.ProductionHistories.FirstOrDefault(t => t.ClientId == e.ProductionHistoryId);
                            if (item != null)
                                e.ServerId = item.ProductionHistoryId;
                        }
                    }
                    adapter.SaveEntityCollection(production_histories);

                    var production_history_downtime_events = (EntityCollection<ProductionHistoryDowntimeEventEntity>)adapter.FetchQuery(production_history_downtime_event_qry);
                    foreach (var e in production_history_downtime_events)
                    {
                        if (e.SyncStatus == (byte)SyncStatus.SyncInProgress)
                            e.SyncStatus = (byte)SyncStatus.InSync;
                        if (!e.ServerId.HasValue)
                        {
                            var item = response.LocalData.ProductionHistoryDowntimeEvents.FirstOrDefault(t => t.ClientId == e.ProductionHistoryDowntimeEventId);
                            if (item != null)
                                e.ServerId = item.ProductionHistoryDowntimeEventId;
                        }
                    }
                    adapter.SaveEntityCollection(production_history_downtime_events);

                    adapter.Commit();

                    // Delete items not from this CellShift
                    VisiBoard.instance().clearOldData();

                    return new ServiceBaseResponse { Success = true };
                }
                catch (Exception e)
                {
                    adapter.Rollback();
                    FileLog.Error("PostSyncFromClientToServer() - ", e);
                    return new ServiceBaseResponse { Error = new ServiceError { Description = ErrorMessages.PrepareSyncClientServerError } };
                }
            }
        }

    }
}
